<?php
class CValidator
{
	protected $model;
	protected $attribute;
	protected $params;
	protected $value;

	public function run($model, $attribute, $params)
	{
		if (!property_exists($model, $attribute))
			throw new Exception('Ошибка запуска валидатора: у модели "'.get_class($model).'" нет атрибута "'.$attribute.'"');

		$this->model = $model;
		$this->attribute = $attribute;
		$this->params = $params;
		$this->value = $model->{$attribute};
	}

	protected function validate()
	{
		return true;
	}
}

class CNumericalValidator extends CValidator
{
	protected function validate()
	{
		if (!$this->params['integer'])
			$this->params['numeric'] = null;

		$valid = true;
		$label = $this->model->attributeLabel($this->attribute);

		foreach ($this->params as $param => $value)
		{
			if ($param == 'integer' && !is_int($this->value))
			{
				$valid = false;
				$this->model->addError($this->attribute, 'Поле '.$label.' должно содержать целочисленное значение');
			}
			elseif ($param == 'numeric' && !is_numeric($this->value))
			{
				$valid = false;
				$this->model->addError($this->attribute, 'Поле '.$label.' должно содержать числовое значение');
			}
			elseif ($param == 'min' && $this->value < $value)
			{
				$valid = false;
				$this->model->addError($this->attribute, 'Поле '.$label.' должно быть не меньше '.$value);
			}
			elseif ($param == 'max' && $this->value > $value)
			{
				$valid = false;
				$this->model->addError($this->attribute, 'Поле '.$label.' должно быть не больше '.$value);
			}
		}

		return $valid;
	}
}

class CRequiredValidator extends CValidator
{
	protected function validate()
	{
		return !empty($this->value);
	}
}

class CLengthValidator extends CValidator
{
	protected function validate()
	{
		$valid = true;
		$label = $this->model->attributeLabel($this->attribute);
		$length = mb_strlen($this->value, 'UTF-8');

		foreach ($this->params as $param => $value)
		{
			if ($param == 'min' && $length < $value)
			{
				$valid = false;
				$this->model->addError($this->attribute, 'Длина значения в поле '.$label.' не должна быть меньше '.$value);
			}
			elseif ($param == 'max' && $length > $value)
			{
				$valid = false;
				$this->model->addError($this->attribute, 'Длина значения в поле '.$label.' не должна превышать '.$value);
			}
		}

		return $valid;
	}
}

class CEmailValidator extends CValidator
{
	protected function validate()
	{
		if (!filter_var($this->value, FILTER_VALIDATE_EMAIL))
		{
			$label = $this->model->attributeLabel($this->attribute);
			$this->model->addError($this->attribute, 'В поле '.$label.' указан неверный адрес эл. почты');
			return false;
		}
		else
			return true;
	}
}